/*
 * Copyright 2018 the original author or authors.
 *
 * you can use the file or import project.but Do not take legal responsibility.
 * Only for learning communication.
 *
 * Java compiled version 1.8 or higher
 *
 *
 *
 *
 */

package org.liang.javasource.excel;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.liang.javasource.bean.BeanAttrsInfo;
import org.liang.javasource.bean.BeanInfo;
import org.liang.javasource.config.ClassConfig;

/**
 * 读取excel接口文档，记录javabean的类信息
 * 
 * @author houliang
 * @date 2018年3月5日
 */
public abstract class CreateExampleExcel {
    private static ClassConfig CONFIG_G = null;// 全局配置信息
    private static boolean isReadRow = false;// 是否需要读取的行

    public static List<BeanInfo> readExcelData(ClassConfig config) {

	CONFIG_G = config;
	String excelPath = config.filePath;
	Integer[] sheets = config.sheets;
	Workbook wb = getWorkbook(excelPath);
	if (wb == null) {
	    return null;
	}
	// 初始化读取的sheets
	int sheetNum = wb.getNumberOfSheets();
	if (sheets == null) {
	    sheets = new Integer[sheetNum];
	    for (int i = 0; i < sheetNum; i++) {
		sheets[i] = i;
	    }
	}
	// 生成javaCode对象
	List<BeanInfo> list = new ArrayList<BeanInfo>();
	for (int i = 0; i < sheets.length; i++) {
	    int n = sheets[i];
	    if (n > sheetNum) {
		continue;
	    }
	    Sheet sheet = wb.getSheetAt(n); // 获取第一个sheet表
	    String sheetName = sheet.getSheetName();
	    System.out.println("sheetName：" + sheetName);
	    List<BeanInfo> listTemp = readSheet(sheet);
	    list.addAll(listTemp);
	}

	try {
	    wb.close();
	} catch (IOException e) {
	    e.printStackTrace();
	}

	return list;
    }

    private static List<BeanInfo> readSheet(Sheet sheet) {
	List<BeanInfo> list = new ArrayList<BeanInfo>();
	List<BeanAttrsInfo> attrList = new ArrayList<BeanAttrsInfo>();// 属性
	Set<String> pgs = new HashSet<String>();// 导入包
	BeanInfo beanInfo = new BeanInfo();// javaBean对象
	int lastNum = sheet.getLastRowNum();

	for (int i = 0; i <= lastNum; i++) {
	    Row rowData = sheet.getRow(i);// 读取行

	    try {
		if (rowData == null) {
		    continue;
		}
		String startFlag = isStartFlag(rowData);

		if (isReadRow && "start".equals(startFlag)) {

		    boolean isOverride = false;// 是否覆盖javaCode，默认不覆盖

		    Object cell9 = getCellValue(rowData.getCell(9));
		    if (cell9 != null) {
			isOverride = (Boolean) cell9;
		    }

		    Object cell11 = getCellValue(rowData.getCell(11));
		    if (cell11 != null) {
			CONFIG_G.packageName = cell11.toString();
		    }

		    String className = getCellValue(rowData.getCell(0)).toString() + CONFIG_G.classSuffix;
		    String classComment = getCellValue(rowData.getCell(1)).toString();
		    beanInfo = new BeanInfo();
		    beanInfo.setClassName(className);
		    beanInfo.setClassComment(classComment);
		    beanInfo.setAuthor(CONFIG_G.author);
		    beanInfo.setClassPackage(CONFIG_G.packageName);

		    String path = CONFIG_G.createPath;
		    if (StringUtils.isBlank(path)) {
			File f = new File("");
			path = f.getAbsolutePath() + "\\src\\main\\java";
		    }
		    beanInfo.setClassPath(path);
		    beanInfo.cover = isOverride;
		    attrList.clear();
		    pgs.clear();
		} else if (!isReadRow && "end".equals(startFlag)) {

		    addBeanAttrs(rowData, attrList);// 读取行，并添加属性
		    beanInfo.setAttrList(attrList);
		    beanInfo.setImportPackage(pgs);

		    dealBean(beanInfo);

		    BeanInfo clone = beanInfo.clone();
		    list.add(clone);
		} else if (isReadRow) {
		    addBeanAttrs(rowData, attrList);// 读取行，并添加属性
		}

	    } catch (Exception e) {
		System.err.println("第" + (i + 1) + "行异常，异常信息：");
		e.printStackTrace();
		throw new RuntimeException();
	    }

	}

	return list;
    }

    // 添加业务逻辑，判断是否为request或者response类型的class处理
    private static void dealBean(BeanInfo beanInfo) {
	Set<String> pgs = beanInfo.getImportPackage();

	// 是否添加父类规则
	if (CONFIG_G.baseDtoRule) {

	    String className = beanInfo.getClassName();

	    if (className.contains("Request")) {
		beanInfo.setBaseDtoRule(true);
		beanInfo.setParentClass("BaseDTO");
		pgs.add("com.juneyaoair.horder.dto.BaseDTO");
	    } else if (className.contains("Response")) {
		beanInfo.setBaseDtoRule(true);
		beanInfo.setParentClass("BaseResultDTO");
		pgs.add("com.juneyaoair.horder.dto.BaseResultDTO");
	    }

	    List<BeanAttrsInfo> ls = beanInfo.getAttrList().stream().filter(o -> filerAttr(o.getName()))
		    .collect(Collectors.toList());
	    beanInfo.setAttrList(ls);
	    
	   boolean hasList = beanInfo.getAttrList().stream().anyMatch(obj -> obj.getType().contains("List"));
	   if(hasList) {
	       beanInfo.getImportPackage().add("java.util.List");
	   }
	    
	}

    }

    /*
     * 过滤属性
     */
    private static boolean filerAttr(String attrName) {

	if (attrName.equalsIgnoreCase("version")) {
	    return false;
	}
	if (attrName.equalsIgnoreCase("channelCode")) {
	    return false;
	}
	if (attrName.equalsIgnoreCase("userNo")) {
	    return false;
	}
	if (attrName.equalsIgnoreCase("resultCode")) {
	    return false;
	}
	if (attrName.equalsIgnoreCase("errorInfo")) {
	    return false;
	}
	return true;
    }

    private static void addBeanAttrs(Row rowData, List<BeanAttrsInfo> attrList) {
	String proName = getCellValue(rowData.getCell(0)).toString();
	String name = proName;
	if ("参数".equals(proName)) {
	    return;
	}
	// 忽略
	Object obj = getCellValue(rowData.getCell(10));
	if (obj != null) {
	    boolean isIg = (Boolean) obj;
	    if (isIg) {
		return;
	    }
	}
	// 是否首字母转换小写
	if (CONFIG_G.firstToLowercase) {
	    proName = proName.substring(0, 1).toLowerCase() + proName.substring(1);
	}

	String proType = getCellValue(rowData.getCell(1)).toString().trim();
	proType = transType(proType);// 类型转换，对象+Dto，数组转换List，基本类型不变

	if ("Int".equals(proType) || "Int16".equals(proType)) {
	    proType = "int";
	}

	String proDesc = getCellValue(rowData.getCell(3)).toString();
	Object proDesc2 = getCellValue(rowData.getCell(4));
	String commentDesc = proDesc2 == null ? ""
		: proDesc2.toString().replaceAll("\r\n", "").replaceAll("\r", "").replaceAll("\n", "");

	attrList.add(new BeanAttrsInfo(name, proName, proType, proDesc, commentDesc));
    }

    private static String isStartFlag(Row rowData) {
	Object startObj = getCellValue(rowData.getCell(8));
	if (startObj == null) {
	    return null;
	}
	if ("start".equals(startObj.toString())) {
	    isReadRow = true;// 开始读取数据行
	    return "start";
	} else if ("end".equals(startObj.toString())) {
	    isReadRow = false;// 开始读取数据行
	    return "end";
	}
	return null;
    }

    private static Object getCellValue(Cell cell) {
	Object object = null;
	if (cell == null) {
	    return object;
	}
	switch (cell.getCellTypeEnum()) {
	case NUMERIC:
	    object = cell.getNumericCellValue();
	    break;
	case STRING:
	    object = cell.getStringCellValue();
	    break;
	case FORMULA:
	    object = cell.getCellFormula();
	    break;
	case BLANK:
	    // object = cell.getStringCellValue();
	    break;
	case BOOLEAN:
	    object = cell.getBooleanCellValue();
	    break;
	case ERROR:
	    object = cell.getStringCellValue();
	    break;
	default:
	    System.out.println("wu");
	    break;
	}
	return object;
    }

    private static String transType(String type) {
	if (noTransType(type)) {
	    return type;
	}

	if (type.contains("List")) {
	    String t = type.replace("List<", "").replace(">", "");
	    if (!noTransType(t)) {
		t = "List<" + t + CONFIG_G.classSuffix + ">";
		return t;
	    } else {
		return type;
	    }
	}

	String t = type;
	if (type.indexOf("]") > 0) {// 数组
	    t = type.replace("[", "").replace("]", "");

	    // 判断对象是否需要加DTO后缀
	    boolean b = noTransType(t);
	    if (!b) {
		t = t + CONFIG_G.classSuffix;
	    }
	    // 数组是否转换为list
	    if (CONFIG_G.arrToList) {
		t = "List<" + t + ">";
	    } else {
		t = t + "[]";
	    }
	} else {
	    t = t + CONFIG_G.classSuffix;
	}
	return t;
    }

    /*
     * 判断是否为基本类型，是返回true
     */
    private static boolean noTransType(String type) {

	for (int i = 0; i < noTransTypes.length; i++) {
	    if (noTransTypes[i].equalsIgnoreCase(type)) {
		return true;
	    }
	}
	return false;
    }

    /**
     * 
     * @param excelPath
     *            相对excel下的文件和绝对路径
     * @return
     */
    private static Workbook getWorkbook(String excelPath) {
	Workbook wb = null;
	try {
	    if (StringUtils.isBlank(excelPath)) {
		System.err.println("文件名不能为空" + excelPath);
		return wb;
	    }
	    File f = null;
	    if (excelPath.indexOf("/") == -1 && excelPath.indexOf("\\") == -1) {
		f = new File("src/main/resources/example/" + excelPath);
	    } else {
		f = new File(excelPath);
	    }
	    if (!f.exists()) {
		System.err.println("文件不存在" + f.getAbsolutePath());
		return wb;
	    }

	    InputStream is = new FileInputStream(f);// CreateExampleExcel.class.getClassLoader().getResourceAsStream("excel\\"
						    // + excelPath);
	    wb = WorkbookFactory.create(is);// 这种方式 Excel 2003/2007/2010 都是可以处理的
	} catch (Exception e) {
	    System.out.println("读取文件出错");
	    e.printStackTrace();
	}

	return wb;
    }

    private static final String[] noTransTypes = new String[] { "String", "int", "double", "list", "date", "boolean",
	    "int16", "BigDecimal" };// 不需要转换类型
}
